module uart_tx #(//数据帧发送
	parameter CLK_FREQ = 50_000_000,
	parameter BAUD_RATE = 9600 ,	//9600,19200,38400,57600,115200,.....
	parameter PARITY_STR = "NONE" , // "NONE" "EVEN" "ODD" 是否有校验位
	parameter DATA_FRAME_WIDTH = 8 
)(
	input wire 							clk ,
	input wire 							rst_n ,
	input wire 							frame_en , //tx_start
	input wire [DATA_FRAME_WIDTH-1:0] 	data_frame ,
	output logic 						tx_done ,
	output logic 						uart_tx 
);
	localparam 	IDLE  		= 6'b000_000 ,
				READY 		= 6'b000_001 ,//准备开始
				START_BIT 	= 6'b000_010 ,//开始位
				SHIFT_PRO 	= 6'b000_100 ,//移位输出
				PARITY_BIT 	= 6'b001_000 ,//校验位
				STOP_BIT 	= 6'b010_000 ,//停止位
				DONE 		= 6'b100_000 ;


	logic bps_clk ;
	logic [DATA_FRAME_WIDTH - 1 :0 ] 		dataR ; //data regsiter
	logic [$clog2(DATA_FRAME_WIDTH)-1:0] 	cnt ;	//shift cnt 
	logic									parity_even ;  //奇偶校验
	logic [5:0] 							c_sta 		;
	logic [5:0] 							n_sta		;


	
	/**********是否有校验位***********/
	logic [1:0] verify_mode ;
	generate
		if( PARITY_STR == "ODD")
			assign verify_mode = 2'b01 ;
		else if (PARITY_STR == "EVEN")
			assign verify_mode = 2'b10 ;
		else
			assign verify_mode = 2'b00 ;
	endgenerate
	/**********是否有校验位***********/


	//===================tx_bps_clk_gen==============================
	tx_bps_clk_gen #(
		.CLK_FREQ(CLK_FREQ),
		.BAUD_RATE(BAUD_RATE)
	) tx_bps_clk_gen_module (
		.clk      (clk),
		.rst_n    (rst_n),
		.tx_done  (tx_done),
		.tx_start (frame_en),
		.bps_clk  (bps_clk)
	);
	//===================tx_bps_clk_gen==============================



	//=========================cnt=================================
	always_ff @(posedge clk or negedge rst_n) begin
		if(~rst_n)begin
			cnt <= 'd0 ;
		end else begin
			if(c_sta == SHIFT_PRO && bps_clk == 1'b1 ) begin //如果是在数据移位输出时，并且bps_clk为高
				if(cnt == DATA_FRAME_WIDTH-1)begin
					cnt <= 'd0 ;
				end else begin
					cnt <= cnt + 1'b1 ;
				end
			end
		end
	end

	//=================FSM ========================================
	always_ff @(posedge clk or negedge rst_n)begin
		if(~rst_n)begin
			c_sta <= 6'd0 ;
		end else begin
			c_sta <= n_sta ;
		end
	end

	always_comb begin
		case(c_sta)
			IDEL 		: n_sta = frame_en 		? READY	 	: IDLE 					;
			READY 		: n_sta = (bps_clk ) 	? START_BIT : READY 				;
			START_BIT	: n_sta = (bps_clk ) 	? SHIFT_PRO :START_BIT 				;
			SHIFT_PRO 	: n_sta = ((cnt == DATA_FRAME_WIDTH-1) && bps_clk == 1'b1)  ? PARITY_BIT : SHIFT_PRO 			;
			PARITY_BIT 	: n_sta = (bps_clk  ) 	? STOP_BIT 	: PARITY_BIT 			;
			STOP_BIT 	: n_sta = (bps_clk  ) 	? DONE 		: STOP_BIT 				;
			DONE 		: n_sta = IDLE ;
			default : begin n_sta = IDEL ; end
		endcase // c_sta
	end

	always_ff @(posedge clk or negedge rst_n) begin : proc_dataR
		if(~rst_n) begin
			dataR <= 'd0;
			uart_tx <= 1'b1 ;
			tx_done <= 1'b0 ;
			parity_even <= 1'b0 ;
		end else begin
			case(n_sta)
				IDLE : begin
					dataR <= 'd0 ;
					tx_done <= 1'd0 ;
					uart_tx <= 1'b1 ;
				end
				READY : begin
					dataR <= 'd0 ;
					tx_done <= 'd0;
					uart_tx <= 1'b1 ;
				end
				START_BIT : begin
					dataR <= data_frame ;
					parity_even <= ^data_frame ; //归异或
					uart_tx <= 1'b0 ;
					tx_done <= 1'b0 ;
				end
				SHIFT_PRO : begin	
					if(bps_clk == 1'b1) begin
						dataR <= {1'b0,dataR[DATA_FRAME_WIDTH-1:1]};
						uart_tx <= dataR[0];
					end else begin
						dataR <= dataR ;
						uart_tx <= uart_tx ;
					end
					tx_done <= 1'b0 ;
				end
				PARITY_BIT:begin
					dataR <=dataR ;
					tx_done <= 1'b0 ;
					case(verify_mode)
						2'b00 : uart_tx <= 1'b1 ; //无校验，多发一位停止位
						2'b01 : uart_tx <= ~parity_even ;
						2'b10 : uart_tx <= parity_even  ;
						default: uart_tx <= 1'b1 ;
					endcase // verify_modecase
				end
				STOP_BIT: uart_tx <= 1'b1 ;

				DONE 	: tx_done <= 1'b1 ;
				default : begin
					dataR <= 'd0 ;
					uart_tx <= 1'b1 ;
					tx_done <= 1'b0 ;
					parity_even <= 1'b0 ;
				end
			endcase
		end
	end
endmodule : uart_tx